#include "ObjectManager.h"
#include <cassert>
#include "StaticObject.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "../SGD Wrappers/SGD_AudioManager.h"
#include "Player.h"
#include "GameplayState.h"
#include "Game.h"
#include "TileSystem.h"
#include "ParticleSystem.h"

ObjectManager::ObjectManager()
{
	m_tTile = new TileSystem();

}
ObjectManager::~ObjectManager()
{
	delete m_tTile;
}

/*******************/
// Get All Objects	//
/*******************/
std::vector<BaseObject*>* ObjectManager::GetAllObjects()
{
	return &m_pObjects;
}

void ObjectManager::AddObjectTable(BaseObject* object, unsigned int bucket)
{
	assert(object != nullptr && " ObjectManager::AddObject - parameter BaseObject cannot be null");

	if (bucket >= m_tObjects.size())
		m_tObjects.resize(bucket + 1);


	m_tObjects[bucket].push_back(object);

	object->AddRef();
}

/***************************************/
// Remove Object from any bucket		//
/***************************************/
void ObjectManager::RemoveObject(BaseObject * pObject)
{
	assert(m_bIterating == false && " ObjectManager::RemoveObject - cannot remove while iterating ");

	// Validate parameters
	assert(pObject != nullptr && "ObjectManager::RemoveObject - cannot remove NULL");

	// Try and find Object in any bucket
	for (unsigned short i = 0; i < m_pObjects.size(); i++)
	{
		if (m_pObjects.at(i) == pObject)
		{
			delete m_pObjects.at(i);
			m_pObjects.at(i) = nullptr;
		}
	}
}

/************************/
// Remove all Objects   //
/************************/
void ObjectManager::RemoveAll(void)
{
	assert(m_bIterating == false && " ObjectManager::RemoveAll - cannot remove while iterating ");

	// Lock iterator
	m_bIterating = true;
	{
		for (unsigned int i = 0; i < m_pObjects.size(); i++)
		{
			if (m_pObjects[i] != nullptr)
				m_pObjects[i]->Release();
			m_pObjects[i] = nullptr;
		}
	}

	for (unsigned int i = 0; i < m_tObjects.size(); i++)
	{
		for (unsigned int j = 0; j < m_tObjects[i].size(); j++)
		{
			m_tObjects.at(i).at(j)->Release();
			m_tObjects.at(i).at(j) = nullptr;
		}
	}
	// unlock iterator
	m_bIterating = false;

	// clear table
	m_pObjects.clear();
}

/************************/
// Update all Objects   //
/************************/
void ObjectManager::UpdateAll(float dt)
{
	//assert(m_bIterating == false && " ObjectManager::UpdateAll - cannot remove while iterating ");
	//
	//// lock iterator
	//m_bIterating = true;
	//{
	//	// Update all Objects
	//	for (unsigned int bucket = 0; bucket < m_tObjects.size(); bucket++)
	//	{
	//		ObjectVector& vec = m_tObjects[bucket];
	//		for (unsigned int i = 0; i < vec.size(); i++)
	//			if (vec[i]->GetAlive() &&
	//				abs(vec[i]->GetPosition().x - m_tObjects[1][0]->GetPosition().x) < 600 &&
	//				abs(vec[i]->GetPosition().y - m_tObjects[1][0]->GetPosition().y) < 450)
	//			vec[i]->Update(dt);
	//	}
	//}
	//
	//// unlock iterator
	//m_bIterating = false;

	// lock iterator
	m_bIterating = true;
	{
		m_tTile->Update();

		for (int i = m_tTile->GetStartingX(); i < m_tTile->GetEndingX(); i++)
			for (int j = m_tTile->GetStartingY(); j < m_tTile->GetEndingY(); j++)
				if (m_pObjects[i + j * m_tTile->GetMapWidth()] != nullptr)//  && m_pObjects[i + j * m_tTile->GetMapWidth()]->GetAlive())
					m_pObjects[i + j * m_tTile->GetMapWidth()]->Update(dt);
	}
	//unlock iterator
	m_bIterating = false;


}

/************************/
// Render all Objects   //
/************************/
void ObjectManager::RenderAll(void)
{
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();

	assert(m_bIterating == false && " ObjectManager::RenderAll - cannot remove while iterating ");

	// lock iterator
	m_bIterating = true;
	{
		m_tTile->Render();

		for (int i = m_tTile->GetStartingX(); i < m_tTile->GetEndingX(); i++)
		{
			for (int j = m_tTile->GetStartingY(); j < m_tTile->GetEndingY(); j++)
			{
				if (m_pObjects[i + j * m_tTile->GetMapWidth()] != nullptr)
				{
					m_pObjects[i + j * m_tTile->GetMapWidth()]->Render();
					//pGraphics->DrawRectangle(m_pObjects[i + j * m_tTile->GetMapWidth()]->GetRect(), SGD::Color(0, 0, 0, 0 ), SGD::Color(150, 150, 0, 0));
				}
			}
		}
	}
	//unlock iterator
	m_bIterating = false;
}

/********************/
// Check Collision  //
/********************/
void ObjectManager::CheckCollisions(BaseObject* pOther)
{
	assert(m_bIterating == false && "ObjectManager::CheckCollisions - cannot collide while iterating");


	// lock iterator
	m_bIterating = true;
	{
		for (int i = m_tTile->GetStartingX(); i < m_tTile->GetEndingX(); i++)
		{
			for (int j = m_tTile->GetStartingY(); j < m_tTile->GetEndingY(); j++)
			{
				if (m_pObjects[i + j * m_tTile->GetMapWidth()] != nullptr && m_pObjects[i + j * m_tTile->GetMapWidth()]->GetAlive())
					if (pOther->GetRect().IsIntersecting(m_pObjects[i + j * m_tTile->GetMapWidth()]->GetRect()))
					{
						pOther->HandleCollision(m_pObjects[i + j * m_tTile->GetMapWidth()]);
						m_pObjects[i + j * m_tTile->GetMapWidth()]->HandleCollision(pOther);
					}
			}
		}
	}
	//unlock iterator
	m_bIterating = false;
}

int ObjectManager::CheckPointInCollision(SGD::Point point)
{
	//assert(m_bIterating == false && "ObjectManager::CheckCollisions - cannot collide while iterating");


	//// lock iterator
	//m_bIterating = true;

	for (int i = m_tTile->GetStartingX(); i < m_tTile->GetEndingX(); i++)
	{
		for (int j = m_tTile->GetStartingY(); j < m_tTile->GetEndingY(); j++)
		{
			if (m_pObjects[i + j * m_tTile->GetMapWidth()] != nullptr && m_pObjects[i + j * m_tTile->GetMapWidth()]->GetAlive())
				if (point.IsWithinRectangle(m_pObjects[i + j * m_tTile->GetMapWidth()]->GetRect()))
				{
					if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::PhaseWall)
						return 2;
					else if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::Bomb)
						return 0;
					else if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::PortalMenu)
						return 0;
					else if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::PortalNext)
						return 0;
					else if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::PortalReset)
						return 0;
					else if (static_cast<StaticObject*>(m_pObjects[i + j * m_tTile->GetMapWidth()])->GetObjectType() == ObjectType::Hookable)
						return 0;
					else
						return 1;
				}
		}
	}

	////unlock iterator
	//m_bIterating = false;

	return false;
}

/*********************************/
// Respawn all objects in bucket //
/*********************************/
void ObjectManager::Respawn(unsigned int bucket)
{
	//assert(bucket < m_tObjects.size() && "ObjectManager::Respawn() - Invalid Bucket");
	if (!m_tObjects.size())
		return;

	ObjectVector& vec = m_tObjects[bucket];
	for (unsigned int i = 0; i < vec.size(); i++)
	{
		if (vec[i]->GetParticle(0) != nullptr)
		{
			vec[i]->GetParticle(0)->GetEmitter()->GetAliveVec().clear();
			vec[i]->GetParticle(0)->GetEmitter()->SetHasLooped(false);
		}
		dynamic_cast<StaticObject*>(vec[i])->SetWasTriggered(false);
		vec[i]->SetAlive(true);
	}
}

void ObjectManager::UnLoadAll()
{

	SGD::GraphicsManager* graphics = SGD::GraphicsManager::GetInstance();
	SGD::AudioManager * audio = SGD::AudioManager::GetInstance();
	std::vector<SGD::HTexture> unloadedTexture;

	for (unsigned int i = 0; i < m_tObjects.size(); i++)
	{
		for (unsigned int j = 0; j < m_tObjects[i].size(); j++)
		{
			if (j == 0)
				unloadedTexture.push_back(m_tObjects.at(i)[j]->GetImage());
			bool found = false;

			for (unsigned int k = 0; k < unloadedTexture.size(); k++)
			{
				if (m_tObjects.at(i)[j]->GetImage() == unloadedTexture[k])
					found = true;
			}

			if (!found)
			{
				unloadedTexture.push_back(m_tObjects.at(i)[j]->GetImage());
				graphics->UnloadTexture(m_tObjects.at(i)[j]->GetImage());
			}

			//if (m_tObjects.at(i).at(j)->GetImage() != SGD::INVALID_HANDLE)
			//{
			//	graphics->UnloadTexture(m_tObjects.at(i)[j]->GetImage());
			//	//m_tObjects.at(i)[j]->SetImage(SGD::INVALID_HANDLE);
			//}

			if (m_tObjects.at(i)[j]->GetAudio() != SGD::INVALID_HANDLE)
				audio->UnloadAudio(m_tObjects.at(i)[j]->GetAudio());
		}
	}
}